package cn.gzmli.dtt.common.utils;

import cn.gzmli.dtt.common.entity.PageInfo;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/**
 * 基于hibernate4的通用泛型数据管理类
 *
 * @author wonderful
 * @param <T> 数据库实体对象类型
 */
@Repository
public class BaseDao<T> {

	private Class<T> entityClass;
	private SessionFactory sessionFactory;
	@Resource(name = "jdbcTemplate")
	private JdbcTemplate jdbcTemplate;
//	@Resource(name = "hibernateTemplate")
//	private HibernateTemplate hibernateTemplate;
	private String entityName;


	@PersistenceContext
	protected EntityManager em;

	@Autowired
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	public SessionFactory getSessionFactory() {
		return this.sessionFactory;
	}
	private Session getCurrentSession() {
		//Hibernate4.x会话获取方式
//		return sessionFactory.getCurrentSession();
		//SpringBoot2.x Hibernate5.x的会话获取方式
		Session session = em.unwrap( Session.class );
		return session;
	}
	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	/**
	 * 无参构造方法，检测泛型参数T的合法性
	 */
	@SuppressWarnings("unchecked")
	public BaseDao() {
		Type type = this.getClass().getGenericSuperclass();
		if (type instanceof ParameterizedType) {
//			throw new RuntimeException("没有传递类型参数T");
			ParameterizedType pt = (ParameterizedType) type;
			this.entityClass = ((Class<T>) pt.getActualTypeArguments()[0]);
		}else{
			this.entityClass = (Class<T>) type;
		}
		this.entityName = this.entityClass.getName();
		this.entityName = this.entityName.substring(this.entityName.lastIndexOf(".") + 1);

	}

	public Serializable insert(T entity) throws Exception {
		return getCurrentSession().save(entityName,entity);
	}

	public void update(T entity) throws Exception {
		getCurrentSession().merge(entityName,entity);
	}

	public void update2(T entity) throws Exception {
		getCurrentSession().update(entity);
	}

	public void delete(T entity) throws Exception {
		getCurrentSession().delete(getCurrentSession().merge(entityName,entity));
	}


	public <T>T get(Serializable id) throws Exception {
		return (T) getCurrentSession().get(this.entityClass, id);
	}

	public <E> E get(Class<E> cla, Serializable id) throws Exception {
		return (E) getCurrentSession().get(cla, id);
	}

	@SuppressWarnings("unchecked")
	public List<T> queryEntityByPage(Map<String, String> condition,
                                     PageInfo pageInfo) throws Exception {

		String tempEntityName = "entity_" + entityName;
		String hql = "SELECT " + tempEntityName + " FROM " + entityName
				+ " AS " + tempEntityName + " WHERE ";
		String orderBy=null;
		if (condition != null && condition.size() > 0) {
			Set<String> keys = condition.keySet();
			for (String key : keys) {
				if(key.contains("ORDER BY")||key.contains("order by")){
					orderBy=key+" "+tempEntityName+"."+condition.get(key);
					continue;
				}
				if(key.contains("REPEATER")){
					hql+=" " + tempEntityName + "." + key.replaceAll("REPEATER\\d+","") + " "
							+ condition.get(key) + " AND ";
					continue;
				}
				if(key.contains(" OR ")||key.contains(" or ")){
					String keyArray[] = null;
					if(key.contains(" OR ")){
						keyArray = key.split(" OR ");
					}else{
						keyArray = key.split(" or ");
					}
					for(int i=0;i<keyArray.length;i++){
						if(keyArray.length-1>i){
							hql+=" (" + tempEntityName + "." + keyArray[i] + condition.get(key) + " OR ";
						}else{
							hql+=tempEntityName + "." + keyArray[i] + condition.get(key) + ")";
						}
					}
					hql+=" AND ";
					continue;
				}
				if(key.contains(" IN ")||key.contains(" in ")||key.contains("NOT IN")||key.contains("not in")){
					hql+=" " + tempEntityName + "." + key + condition.get(key) + " AND ";
					continue;
				}
				hql+=" " + tempEntityName + "." + key + " "
						+ condition.get(key) + " AND ";

			}

		}

		if((orderBy!=null&&condition != null && condition.size()==1)||
				(orderBy==null&&condition != null && condition.size()==0)||
				(orderBy==null&&condition == null)
				){
			hql = hql.replaceAll("(WHERE){1}", "");
		}

		if (hql.lastIndexOf("AND") > 0)
			hql = hql.substring(0, hql.lastIndexOf("AND"));
		if(orderBy!=null){
			hql+=" "+orderBy+" ";
		}
		Query query = this.getCurrentSession().createQuery(
				hql.replaceAll("SELECT[\\W\\w]+" + tempEntityName + " FROM",
						"SELECT COUNT(*) FROM"));
		Object object = query.list().get(0);
		pageInfo.setTotalRows(((Long) object).intValue());
		query = this.getCurrentSession().createQuery(hql);
		query.setFirstResult((pageInfo.getCurPage() - 1) * pageInfo.getPageSize());
		query.setMaxResults(pageInfo.getPageSize());

		pageInfo.createTotalPages();
		return query.list();
	}

	private List<T> returnData(List<T> data, PageInfo pageInfo){
		Set<Object> set = new LinkedHashSet<>();
		for (Object o : data){
			if (o instanceof Object[]){
				for (Object obj : (Object[])o){
					if (obj.getClass().isAssignableFrom(this.entityClass)){
						set.add(obj);
					}
				}
			}else{
				set.add(o);
			}
		}
		if (pageInfo!=null&&set.size()>0){
			int begin = (pageInfo.getCurPage() - 1) * pageInfo.getPageSize();
			int end = pageInfo.getCurPage()*pageInfo.getPageSize();
			return new ArrayList(set).subList(begin>set.size()?set.size():begin, end>set.size()?set.size():end);
		}else{
			return new ArrayList(set);
		}
	}

	/**
	 * Hibernate分页查询
	 * @param condition 过滤条件对象
	 * @param pageInfo 分页对象
	 * @return
	 * @throws Exception
	 */
	public List<T> queryEntityByPage(
			DetachedCriteria condition,
			PageInfo pageInfo
	) throws Exception {
		Criteria query = condition.getExecutableCriteria(this.getCurrentSession());
		query.setProjection(Projections.rowCount());
		Long totalCount =(Long) query.uniqueResult();
		pageInfo.setTotalRows(totalCount.intValue());
//		query.setFirstResult((pageInfo.getCurPage() - 1) * pageInfo.getPageSize());
//		query.setMaxResults(pageInfo.getPageSize());
		pageInfo.createTotalPages();

//		query.add(Restrictions.sqlRestriction(" 1=1 GROUP BY this_.id "));
		List data = query.setProjection(null).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
//		List data = query.setProjection(null).list();
		return returnData(data, pageInfo);
	}

	public List<T> queryEntity(Map<String, String> condition) throws Exception {

		String tempEntityName = "entity_" + entityName;
		String hql = "SELECT " + tempEntityName + " FROM " + entityName
				+ " AS " + tempEntityName + " WHERE ";
		String orderBy=null;
		if (condition != null && condition.size() > 0) {
			Set<String> keys = condition.keySet();
			for (String key : keys) {

				if(key.contains("ORDER BY")||key.contains("order by")){

					if(condition.get(key)!=null
							&&condition.get(key).toString().indexOf(",")==-1){
						orderBy=key+" "+tempEntityName+"."+condition.get(key);
					}else if(condition.get(key)!=null){
						String values[]=condition.get(key).toString().split(",");
						for(int i=0;i<values.length;i++){
							if(i==0){
							orderBy=key+" "+tempEntityName+"."+values[i];
							}else {
							orderBy+=","+tempEntityName+"."+values[i];
							}
						}

					}

					continue;
				}
				if(key.contains("REPEATER")){
					hql+=" " + tempEntityName + "." + key.replaceAll("REPEATER\\d+","") + " "
							+ condition.get(key) + " AND ";
					continue;
				}
				hql+=" " + tempEntityName + "." + key + " "
						+ condition.get(key) + " AND ";

			}

		} if((orderBy!=null&&condition != null && condition.size()==1)||
				(orderBy==null&&condition != null && condition.size()==0)||
				(orderBy==null&&condition == null)
				){
			hql = hql.replaceAll("(WHERE){1}", "");
		}

		if (hql.lastIndexOf("AND") > 0)
			hql = hql.substring(0, hql.lastIndexOf("AND"));

		if(orderBy!=null){
			hql+=" "+orderBy+" ";
		}

		Query query = this.getCurrentSession().createQuery(hql);
		return query.list();
	}

	public List<T> queryEntity(DetachedCriteria condition) throws Exception {
		List data = condition.getExecutableCriteria(this.getCurrentSession()).list();
		return returnData(data, null);
	}
	/**
	 * 返回唯一的实体，针对只返回一个实体对象的查询
	 * @param condition 条件map
	 * @return          唯一实体
	 * @throws Exception
	 */
	public T queryOnlyEntity(Map<String, String> condition) throws Exception {

		String tempEntityName = "entity_" + entityName;
		String hql = "SELECT " + tempEntityName + " FROM " + entityName
				+ " AS " + tempEntityName + " WHERE ";
		String orderBy=null;
		if (condition != null && condition.size() > 0) {
			Set<String> keys = condition.keySet();
			for (String key : keys) {
				if(key.contains("ORDER BY")||key.contains("order by")){
					orderBy=key+" "+tempEntityName+"."+condition.get(key);
					continue;
				}
				if(key.contains("REPEATER")){
					hql+=" " + tempEntityName + "." + key.replaceAll("REPEATER\\d+","") + " "
							+ condition.get(key) + " AND ";
					continue;
				}
				hql+=" " + tempEntityName + "." + key + " "
						+ condition.get(key) + " AND ";

			}

		} if((orderBy!=null&&condition != null && condition.size()==1)||
				(orderBy==null&&condition != null && condition.size()==0)||
				(orderBy==null&&condition == null)
				){
			hql = hql.replaceAll("(WHERE){1}", "");
		}

		if (hql.lastIndexOf("AND") > 0)
			hql = hql.substring(0, hql.lastIndexOf("AND"));

		if(orderBy!=null){
			hql+=" "+orderBy+" ";
		}
		T entity=null;
		this.getCurrentSession().clear();
		Query query = this.getCurrentSession().createQuery(hql);
		this.getCurrentSession().clear();
		List<T> entityLst= query.list();
		if(entityLst!=null&&entityLst.size()==1)
			entity=entityLst.get(0);

		return entity;
	}

	public List<T> queryEntity(Map<String, String> condition, int topSize) throws Exception {

		String tempEntityName = "entity_" + entityName;
		String hql = "SELECT " + tempEntityName + " FROM " + entityName
				+ " AS " + tempEntityName + " WHERE ";
		String orderBy=null;
		if (condition != null && condition.size() > 0) {
			Set<String> keys = condition.keySet();
			for (String key : keys) {
				if(key.contains("ORDER BY")||key.contains("order by")){
					orderBy=key+" "+tempEntityName+"."+condition.get(key);
					continue;
				}
				if(key.contains("REPEATER")){
					hql+=" " + tempEntityName + "." + key.replaceAll("REPEATER\\d+","") + " "
							+ condition.get(key) + " AND ";
					continue;
				}
				hql+=" " + tempEntityName + "." + key + " "
						+ condition.get(key) + " AND ";

			}

		} if((orderBy!=null&&condition != null && condition.size()==1)||
				(orderBy==null&&condition != null && condition.size()==0)||
				(orderBy==null&&condition == null)
				){
			hql = hql.replaceAll("(WHERE){1}", "");
		}
		if (hql.lastIndexOf("AND") > 0)
			hql = hql.substring(0, hql.lastIndexOf("AND"));
		if(orderBy!=null){
			hql+=" "+orderBy+" ";
		}
		Query query = this.getCurrentSession().createQuery(hql);
		query.setMaxResults(topSize);
		return query.list();
	}
	/**
	 *
	 * @param orderCond 排序SQL字符串
	 * @return
	 * @throws Exception
	 */
	public List<T> queryEntityAll(String orderCond)throws Exception {
		String tempEntityName = "entity_" + entityName;
		String hql = "SELECT " + tempEntityName + " FROM " + entityName
				+ " AS " + tempEntityName ;
		if(orderCond!=null)
			hql+=" "+orderCond;
		Query query = this.getCurrentSession().createQuery(hql);
		return query.list();

	}

	public List<T> queryEntityAll()throws Exception {
		String tempEntityName = "entity_" + entityName;
		String hql = "SELECT " + tempEntityName + " FROM " + entityName
				+ " AS " + tempEntityName ;
		Query query = this.getCurrentSession().createQuery(hql);
		return query.list();
	}
}
